package com.aizuda.boot.modules.flw.flow;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.boot.modules.business.contract.entity.ContractEntity;
import com.aizuda.boot.modules.business.contract.entity.ContractFieldEntity;
import com.aizuda.boot.modules.business.contract.entity.ContractFieldValueEntity;
import com.aizuda.boot.modules.business.contract.mapper.ContractFieldValueMapper;
import com.aizuda.boot.modules.business.contract.service.ContractFieldService;
import com.aizuda.boot.modules.business.contract.service.ContractService;
import com.aizuda.boot.modules.business.contractNumber.domain.ContractNumberEvent;
import com.aizuda.boot.modules.business.feishu.service.FeiShuApprovalService;
import com.aizuda.boot.modules.common.MessageEvent;
import com.aizuda.boot.modules.common.constant.enums.ContractStatusEnum;
import com.aizuda.boot.modules.common.constant.enums.GenerateTimingEnums;
import com.aizuda.boot.modules.common.constant.enums.SystemFieldsEnum;
import com.aizuda.boot.modules.flw.entity.ApprovalContent;
import com.aizuda.boot.modules.flw.entity.FlwProcessApproval;
import com.aizuda.boot.modules.flw.entity.dto.NextNodesDTO;
import com.aizuda.boot.modules.flw.mapper.FlowlongMapper;
import com.aizuda.boot.modules.flw.service.IFlwProcessApprovalService;
import com.aizuda.boot.modules.flw.service.IFlwProcessService;
import com.aizuda.boot.modules.flw.service.IFlwProcessTaskService;
import com.aizuda.boot.modules.system.entity.SysUser;
import com.aizuda.boot.modules.system.entity.enums.BusinessType;
import com.aizuda.boot.modules.system.service.ISysUserRoleService;
import com.aizuda.boot.modules.system.service.ISysUserService;
import com.aizuda.bpm.engine.FlowLongEngine;
import com.aizuda.bpm.engine.core.FlowCreator;
import com.aizuda.bpm.engine.core.enums.*;
import com.aizuda.bpm.engine.entity.*;
import com.aizuda.bpm.engine.listener.TaskListener;
import com.aizuda.bpm.engine.model.NodeAssignee;
import com.aizuda.bpm.engine.model.NodeModel;
import com.aizuda.bpm.engine.model.ProcessModel;
import com.aizuda.common.toolkit.CollectionUtils;
import com.aizuda.common.toolkit.StringUtils;
import com.aizuda.core.api.ApiAssert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Slf4j
@Component
public class FlowTaskListener implements TaskListener {

    @Resource
    private IFlwProcessApprovalService flwProcessApprovalService;
    @Resource
    private FlowLongEngine flowLongEngine;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private ISysUserRoleService userRoleService;
    @Resource
    @Lazy
    private IFlwProcessTaskService flwProcessTaskService;
    @Resource
    private FlowlongMapper flowlongMapper;
    @Lazy
    @Resource
    private ContractService contractService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ContractFieldService contractFieldService;
    @Resource
    private ContractFieldValueMapper contractFieldValueMapper;
    @Resource
    private FeiShuApprovalService feiShuApprovalService;
    @Resource
    @Lazy
    private IFlwProcessService flwProcessService;

    @Override
    public boolean notify(TaskEventType eventType, Supplier<FlwTask> supplier, List<FlwTaskActor> taskActors,
                          NodeModel nodeModel, FlowCreator flowCreator) {
        // 获取当前任务信息
        FlwTask flwTask = supplier.get();

        //生成合同编号逻辑
        contractNumber(flwTask);

        List<FlwTaskActor> flwTaskActors = resolveTaskActorsWithRetry(flwTask, taskActors, 3, 50);
        if (CollectionUtils.isEmpty(flwTaskActors)) {
            // 引擎在归档前通过线程变量传递的参与者（complete/reject等事件时活动表已清空）
            List<FlwTaskActor> notifyActors = FlowHelper.getNotifyTaskActors();
            if (!CollectionUtils.isEmpty(notifyActors)) {
                flwTaskActors = notifyActors;
            }
        }
        boolean isBusiness = false;
        FlwHisInstance histInstance = flowLongEngine.queryService().getHistInstance(flwTask.getInstanceId());
        if (null == histInstance) {
            return false;
        }
        FlwProcess process = flwProcessService.getById(histInstance.getProcessId());
        if (null == process) {
            return false;
        }
        if (ProcessType.business.eq(process.getProcessType())) {
            isBusiness = true;
        }
        // 无论是否使用，均清理线程变量，避免线程复用造成的污染或内存占用
        FlowHelper.removeNotifyTaskActors();
        final List<FlwTaskActor> finalFlwTaskActors = flwTaskActors;

        // 不进行二次执行自动跳转逻辑，防止出现taskId不存在，退回需要发起人手动审批
        if (TaskEventType.create.eq(eventType) || TaskEventType.recreate.eq(eventType)
                // 重新发起审批创建
                || TaskEventType.reApproveCreate.eq(eventType)) {
            // 获取当前节点信息
            if (null != flwTask) {
                NodeModel currentNodeModel = this.getNodeModel(flwTask, nodeModel);

                // 检查agreeAuto自动跳过逻辑（优先检查）
                if (TaskEventType.create.eq(eventType) && shouldAutoSkipForAgreementAuto(currentNodeModel, flwTask, taskActors)) {
                    log.info("检测到已审批过该流程的审批人，执行自动跳过逻辑，任务ID: {}, 实例ID: {}",
                            flwTask.getId(), flwTask.getInstanceId());
                    return true;
                }

                // 创建人物，发起人自己，自动跳过
                if (TaskEventType.create.eq(eventType) && NodeApproveSelf.AutoSkip.eq(currentNodeModel.getApproveSelf())) {
                    if (NodeSetType.initiatorThemselves.eq(currentNodeModel.getSetType())) {
                        // 发起人自己，执行自动跳转逻辑
                        flowLongEngine.autoJumpTask(flwTask.getId(), flowCreator);
                        return true;
                    } else {
                        // 流程发起人自动跳过处理
                        final FlwInstance instance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
                        if (taskActors.stream().anyMatch(t -> Objects.equals(t.getActorId(), instance.getCreateId())
                                // 当前节点处理人参与父节点审批
                                || flwProcessTaskService.approvedParentNode(flwTask.getParentTaskId(), t.getActorId())
                        )) {
                            // 审批人与提交人为同一人时，执行自动跳转逻辑
                            flowLongEngine.autoJumpTask(flwTask.getId(), FlowCreator.of(instance.getTenantId(),
                                    instance.getCreateId(), instance.getCreateBy()));
                            return true;
                        }
                    }
                } else {
                    // 推送消息，需要勾选【审批提醒】
                    if (Boolean.TRUE.equals(currentNodeModel.getRemind())) {
                        this.sendMessage(flwTask, flowCreator);
                    }
                }
                if (isBusiness) {
                    ThreadUtil.execute(() -> {
                        // 统一解析任务参与者，兼容未直接传递参与者的任务类型
                        List<FlwTaskActor> effectiveActors = resolveTaskActorsWithRetry(flwTask, taskActors, 5, 100);

                        // 同步飞书审批任务与Bot消息
                        feiShuApprovalService.syncTask(eventType, supplier, effectiveActors, flowCreator, 0);

                        // 仅在创建类事件下发送Bot通知，其它事件使用同步更新状态
                        feiShuApprovalService.sendApprovalBot(eventType, supplier, effectiveActors, flowCreator);
                    });
                }

                // 检查是否为归档任务创建，如果是则更新合同状态
                if (TaskType.archive.eq(currentNodeModel.getType())) {
                    log.info("检测到归档任务创建，任务ID: {}, 开始检查合同状态更新", flwTask.getId());
                    checkAndUpdateContractStatusOnArchiveTaskCreate(flwTask);
                }
            }
            // 创建任务直接跳过
            return true;
        }

        if (isBusiness) {
            ThreadUtil.execute(new Runnable() {
                @Override
                public void run() {
                    // 对所有非start事件，统一按解析后的参与者进行同步
                    if (TaskEventType.start.ne(eventType)) {
                        // 同步更新飞书Bot卡片状态
                        feiShuApprovalService.syncApprovalBot(flwTask.getId(), eventType, flowCreator);

                        feiShuApprovalService.syncTask(eventType, supplier, finalFlwTaskActors, flowCreator, 0);
                    }
                }
            });
        }
        if (TaskEventType.other.eq(eventType)) {
            return true;
        }

        // 监听处理其它任务事件
        FlwProcessApproval fpa = new FlwProcessApproval();
        if (null != flwTask) {
            fpa.setInstanceId(flwTask.getInstanceId());
            fpa.setTenantId(flwTask.getTenantId());
            fpa.setTaskId(flwTask.getId());
            if (eventType == TaskEventType.routeJump) {
                fpa.setTaskName(flwTask.getTaskName() + " -> 路由至 -> " + nodeModel.getNodeName());
            } else {
                fpa.setTaskName(flwTask.getTaskName());
            }
            PerformType performType = PerformType.get(flwTask.getPerformType());
            if (performType == PerformType.start && eventType == TaskEventType.start) {
                // 发起
                fpa.setType(1);
            } else {
                if (eventType == TaskEventType.assignment) {
                    TaskType taskType = TaskType.get(flwTask.getTaskType());
                    if (taskType == TaskType.transfer) {
                        // 转办、代理人办理完任务直接进入下一个节点
                        fpa.setType(6);
                    } else if (taskType == TaskType.delegate) {
                        // 委派、代理人办理完任务该任务重新归还给原处理人
                        fpa.setType(7);
                    } else if (taskType == TaskType.delegateReturn) {
                        // 委派归还任务
                        fpa.setType(18);
                    }
                }

                // 获取当前节点信息
                NodeModel currentNodeModel = this.getNodeModel(flwTask, nodeModel);
                boolean saveContent = false;
                ApprovalContent content = new ApprovalContent();
                if (TaskEventType.cc.eq(eventType)) {
                    // 自动抄送
                    content.setNodeUserList(currentNodeModel.getNodeAssigneeList());
                    // 对于自动抄送，直接从taskActors获取抄送用户信息并从sys_user表补充完整信息
                    List<NodeAssignee> ccUsers = this.enrichCcUsersFromSysUser(taskActors.stream().map(NodeAssignee::of).toList());
                    content.setCcUserList(ccUsers);
                    saveContent = true;
                    // 推送消息，需要勾选【审批提醒】
                    if (Boolean.TRUE.equals(currentNodeModel.getRemind())) {
                        this.sendMessage(flwTask, flowCreator, currentNodeModel.getNodeAssigneeList());
                    }
                } else {

                    // 其它
                    String opinion = FlowHelper.getProcessApprovalOpinion();
                    if (StringUtils.hasLength(opinion)) {
                        FlowHelper.removeProcessApprovalOpinion();
                        content.setOpinion(opinion);
                        saveContent = true;
                    }

                    // 手动抄送
                    if (TaskEventType.createCc.eq(eventType)) {
                        List<NodeAssignee> ccUsers = taskActors.stream().map(NodeAssignee::of).toList();
                        content.setNodeUserList(ccUsers);
                        // 对于手动抄送，也需要设置ccUserList并补充完整用户信息
                        List<NodeAssignee> enrichedCcUsers = this.enrichCcUsersFromSysUser(ccUsers);
                        content.setCcUserList(enrichedCcUsers);
                        if (null == content.getOpinion()) {
                            content.setOpinion("发起抄送任务");
                            saveContent = true;
                        }
                        // 推送消息
                        this.sendMessage(flwTask, flowCreator, ccUsers);
                    } else {
                        // 对于非抄送任务，查询历史抄送用户列表
                        List<NodeAssignee> ccUserList = this.getCcUsersByTaskId(flwTask.getId());
                        if (CollectionUtils.isNotEmpty(ccUserList)) {
                            content.setCcUserList(ccUserList);
                            saveContent = true;
                        }
                    }
                }

                if (NodeSetType.specifyMembers.eq(currentNodeModel.getSetType())) {
                    // 指定成员类型
                    content.setNodeUserList(currentNodeModel.getNodeAssigneeList());
                    saveContent = true;
                } else if (NodeSetType.role.eq(currentNodeModel.getSetType())) {
                    // 角色类型
                    content.setNodeRoleList(currentNodeModel.getNodeAssigneeList());
                    saveContent = true;
                }

                // 记录是否调用流程
                String callProcess = currentNodeModel.getCallProcess();
                if (StringUtils.hasLength(callProcess)) {
                    content.setCallProcess(callProcess);
                    saveContent = true;
                }

                // 记录审批内容
                if (saveContent) {
                    fpa.setContent(content);
                }
            }

            //用于流程图颜色标记
            fpa.setTaskKey(flwTask.getTaskKey());
        }

        if (TaskEventType.autoComplete.eq(eventType) || TaskEventType.autoReject.eq(eventType)
                || TaskEventType.trigger.eq(eventType)) {
            // 自动审批情况，设置默认处理人信息
            fpa.setCreateId(-1L);
            fpa.setCreateBy("系统机器人");
        } else if (TaskEventType.cc.eq(eventType)) {
            // 抄送事件：有具体抄送人时使用抄送人信息，没有人时使用系统机器人
            if (CollectionUtils.isNotEmpty(taskActors)) {
                // 有具体抄送人，使用第一个抄送人的信息
                FlwTaskActor firstActor = taskActors.get(0);
                fpa.setCreateId(Long.valueOf(firstActor.getActorId()));
                fpa.setCreateBy(firstActor.getActorName());
            } else {
                // 没有具体抄送人，使用系统机器人
                fpa.setCreateId(-1L);
                fpa.setCreateBy("系统机器人");
            }
        }

        if (null == fpa.getType()) {
            // 其它类型转换
            fpa.setType(this.getType(eventType));
        }

        // 处理任务完成事件，检查并更新合同状态
        if (TaskEventType.complete.eq(eventType) && flwTask != null) {
            try {
                checkAndUpdateContractStatusIfLastNode(flwTask);
            } catch (Exception e) {
                log.warn("检查并更新合同状态失败，但不影响审批流程，任务ID: {}", flwTask.getId(), e);
            }
        }

        // 处理子流程启动事件，设置子流程的business_key
        if (TaskEventType.callProcess.eq(eventType) && flwTask != null) {
            try {
                setSubProcessBusinessKey(flwTask, nodeModel);
            } catch (Exception e) {
                log.warn("设置子流程business_key失败，但不影响审批流程，任务ID: {}", flwTask.getId(), e);
            }
        }

        return flwProcessApprovalService.save(fpa);
    }

    private void sendMessage(FlwTask flwTask, FlowCreator flowCreator, List<NodeAssignee> nodeAssigneeList) {
        // 发送抄送任务
        if (CollectionUtils.isEmpty(nodeAssigneeList)) {
            return;
        }
        List<Long> actorIds = nodeAssigneeList.stream().map(t -> Long.valueOf(t.getId())).toList();
        // 获取流程实例的创建人信息
        FlwInstance instance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());

        int contractId = 0;

        // 查询流程是否关联了合同
        String businessKey = instance.getBusinessKey();
        try {
            if (StringUtils.hasLength(businessKey)) {
                contractId = Integer.parseInt(businessKey);
            }
        } catch (Exception e) {
            log.error("解析合同ID失败，businessKey: {}", businessKey, e);
            return;
        }
        String contractName = getFieldValue(contractId, SystemFieldsEnum.CONTRACT_NAME.getCode());
        String applyUser = getFieldValue(contractId, SystemFieldsEnum.APPLY_PEOPLE.getCode());
        String applyName = StringUtils.hasLength(applyUser) ? sysUserService.getById(Long.parseLong(applyUser)).getNickName() : "未知";
        String title = String.format("合同名称：%s，申请人：%s【合同抄送】",
                contractName != null ? contractName : "未知",
                applyName != null ? applyName : "未知");
        String content = String.format("由【%s】发起的合同【%s】已经进入【%s】节点。\n💡 此为抄送通知，您无需进行任何操作，仅供了解流程进展。",
                applyName != null ? applyName : "未获取",
                contractName != null ? contractName : "未获取",
                flwTask.getTaskName());

        // 发送消息
        MessageEvent messageEvent = new MessageEvent();
        messageEvent.setTitle(title);
        messageEvent.setContent(content);
        messageEvent.setCreateId(Long.valueOf(flowCreator.getCreateId()));
        messageEvent.setCreateBy(flowCreator.getCreateBy());
        messageEvent.setCategory(2);
        messageEvent.setBusinessId(flwTask.getInstanceId());
        messageEvent.setBusinessType(BusinessType.flowTodoTask.name());
        messageEvent.setUserIds(actorIds);
        applicationEventPublisher.publishEvent(messageEvent);
    }

    /**
     * 解析任务参与者：
     * 1) 优先使用传入的参与者；
     * 2) 若为空，则在短时间内重试从引擎查询直至得到用户级参与者；
     * 3) 通过重试避免仅有角色/部门占位导致的参与者缺失。
     */
    private List<FlwTaskActor> resolveTaskActorsWithRetry(FlwTask flwTask,
                                                          List<FlwTaskActor> incomingActors,
                                                          int maxAttempts,
                                                          long sleepMillis) {
        if (!CollectionUtils.isEmpty(incomingActors)) {
            return incomingActors;
        }
        List<FlwTaskActor> resolved = new ArrayList<>();
        int attempts = 0;
        while (CollectionUtils.isEmpty(resolved) && attempts < maxAttempts) {
            if (flwTask != null && flwTask.getId() != null) {
                try {
                    resolved = flowLongEngine.queryService().getTaskActorsByTaskId(flwTask.getId());
                } catch (Exception e) {
                    log.warn("查询任务参与者失败，任务ID: {}，重试计数: {}", flwTask.getId(), attempts, e);
                }
            }
            if (CollectionUtils.isEmpty(resolved)) {
                try {
                    Thread.sleep(sleepMillis);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            attempts++;
        }
        return resolved;
    }

    private void is(Long parentTaskId) {

    }

    private NodeModel getNodeModel(FlwTask flwTask, NodeModel nodeModel) {
        if (null == nodeModel) {
            // 不存在情况从数据库中获取
            ProcessModel processModel = flowLongEngine.runtimeService().getProcessModelByInstanceId(flwTask.getInstanceId());
            ApiAssert.isEmpty(processModel, "流程模型节点查询异常");
            return processModel.getNode(flwTask.getTaskKey());
        }
        return nodeModel;
    }

    private int getType(TaskEventType eventType) {
        // 办理
        int type = 3;
        if (eventType == TaskEventType.start) {
            // 发起
            type = 1;
        } else if (eventType == TaskEventType.cc || eventType == TaskEventType.createCc) {
            // 抄送
            type = 2;
        } else if (eventType == TaskEventType.reject) {
            // 驳回
            type = 4;
        } else if (eventType == TaskEventType.claimRole || eventType == TaskEventType.claimDepartment) {
            // 认领
            type = 5;
        } else if (eventType == TaskEventType.jump || eventType == TaskEventType.routeJump
                || eventType == TaskEventType.rejectJump || eventType == TaskEventType.reApproveJump) {
            // 跳转
            type = 8;
        } else if (eventType == TaskEventType.reclaim) {
            // 拿回
            type = 9;
        } else if (eventType == TaskEventType.resume) {
            // 唤醒
            type = 10;
        } else if (eventType == TaskEventType.revoke || eventType == TaskEventType.withdraw) {
            // 撤销
            type = 15;
        } else if (eventType == TaskEventType.terminate) {
            // 终止
            type = 16;
        } else if (eventType == TaskEventType.timeout) {
            // 超时
            type = 17;
        } else if (eventType == TaskEventType.autoJump) {
            // 自动跳转
            type = 19;
        } else if (eventType == TaskEventType.autoComplete) {
            // 自动完成
            type = 20;
        } else if (eventType == TaskEventType.autoReject) {
            // 自动拒绝
            type = 21;
        } else if (eventType == TaskEventType.callProcess) {
            // 调用外部流程任务【办理子流程】
            type = 22;
        } else if (eventType == TaskEventType.trigger) {
            // 触发器任务
            type = 23;
        }
        return type;
    }

    public void sendMessage(FlwTask flwTask, FlowCreator flowCreator) {
        Optional<List<FlwTaskActor>> taskActorsOptional = flowLongEngine.queryService().getActiveTaskActorsByTaskId(flwTask.getId());
        if (taskActorsOptional.isPresent()) {
            List<FlwTaskActor> flwTaskActors = taskActorsOptional.get();
            if (CollectionUtils.isEmpty(flwTaskActors)) {
                // 暂时先不处理，根据具体业务调整
                return;
            }
            List<Long> actorIds = flwTaskActors.stream().map(t -> Long.valueOf(t.getActorId())).toList();
            FlwTaskActor fta = flwTaskActors.get(0);
            if (ActorType.role.eq(fta.getActorType())) {
                // 流程任务处理者为角色情况，查询对应用户ID列表
                actorIds = userRoleService.listUserIdsByRoleIds(actorIds);
            }
            FlwExtInstance extInstance = flowLongEngine.queryService().getExtInstance(flwTask.getInstanceId());
            // 获取流程实例的创建人信息
            FlwInstance instance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
            SysUser user = sysUserService.getById(instance.getCreateId());

            int contractId = 0;

            // 查询流程是否关联了合同
            String businessKey = instance.getBusinessKey();
            try {
                if (StringUtils.hasLength(businessKey)) {
                    contractId = Integer.parseInt(businessKey);
                }
            } catch (Exception e) {
                log.error("解析合同ID失败，businessKey: {}", businessKey, e);
            }
            String title = "流程：" + extInstance.getProcessName() + " 待审批";
            String content = title + " ，当前所在节点：" + flwTask.getTaskName() + " ，流程发起人：" + (null == user ? instance.getCreateBy() : user.getNickName());
            if (contractId != 0) {
                // 关联了合同，发送合同相关信息
                String contractName = getFieldValue(contractId, SystemFieldsEnum.CONTRACT_NAME.getCode());
                String applyUser = getFieldValue(contractId, SystemFieldsEnum.APPLY_PEOPLE.getCode());
                String applyName = StringUtils.hasLength(applyUser) ? sysUserService.getById(Long.parseLong(applyUser)).getNickName() : "未知";
                title = String.format("合同名称：%s，申请人：%s",
                        contractName != null ? contractName : "未知",
                        applyName != null ? applyName : "未知");
                content = String.format("由【%s】发起的合同【%s】已经进入【%s】节点，请尽快处理。",
                        applyName != null ? applyName : "未获取",
                        contractName != null ? contractName : "未获取",
                        flwTask.getTaskName());

            }

            // 发送消息
            MessageEvent messageEvent = new MessageEvent();
            messageEvent.setTitle(title);
            messageEvent.setContent(content);
            messageEvent.setCreateId(Long.valueOf(flowCreator.getCreateId()));
            messageEvent.setCreateBy(flowCreator.getCreateBy());
            messageEvent.setCategory(2);
            messageEvent.setBusinessId(flwTask.getInstanceId());
            messageEvent.setBusinessType(BusinessType.flowTodoTask.name());
            messageEvent.setUserIds(actorIds);
            applicationEventPublisher.publishEvent(messageEvent);
        }
    }


    private String getFieldValue(Integer contractId, String fieldCode) {
        ContractFieldEntity field = contractFieldService.getOne(Wrappers.<ContractFieldEntity>lambdaQuery()
                .eq(ContractFieldEntity::getCode, fieldCode)
                .select(ContractFieldEntity::getId)
                .last("limit 1"));
        ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(Wrappers.<ContractFieldValueEntity>lambdaQuery()
                .eq(ContractFieldValueEntity::getContractId, contractId)
                .eq(ContractFieldValueEntity::getFieldId, field.getId())
                .last("limit 1"));
        return fieldValue.getFieldValue();
    }

    /**
     * 检查是否应该基于agreeAuto配置自动跳过审批
     *
     * @param currentNodeModel 当前节点模型
     * @param flwTask          当前任务
     * @param taskActors       任务审批人列表
     * @return 是否应该自动跳过
     */
    private boolean shouldAutoSkipForAgreementAuto(NodeModel currentNodeModel, FlwTask flwTask, List<FlwTaskActor> taskActors) {
        try {
            // 检查节点配置中的extendConfig.agreeAuto
            Map<String, Object> extendConfig = currentNodeModel.getExtendConfig();
            if (extendConfig == null) {
                return false;
            }

            Object agreeAutoObj = extendConfig.get("agreeAuto");
            if (agreeAutoObj == null) {
                return false;
            }

            // 检查agreeAuto是否为1（自动通过）
            Integer agreeAuto = null;
            if (agreeAutoObj instanceof Integer) {
                agreeAuto = (Integer) agreeAutoObj;
            } else if (agreeAutoObj instanceof String) {
                try {
                    agreeAuto = Integer.parseInt((String) agreeAutoObj);
                } catch (NumberFormatException e) {
                    log.warn("agreeAuto字段格式错误: {}", agreeAutoObj);
                    return false;
                }
            }

            if (agreeAuto == null || !Objects.equals(1, agreeAuto)) {
                // agreeAuto不是1，不自动跳过
                return false;
            }

            log.info("节点配置了agreeAuto=1，检查审批人是否已参与过该流程实例，节点: {}, 任务ID: {}, 实例ID: {}",
                    currentNodeModel.getNodeName(), flwTask.getId(), flwTask.getInstanceId());

            // 检查当前任务的审批人是否已经参与过该流程实例
            boolean hasParticipatedUser = false;
            String participatedActorId = null;
            String participatedActorName = null;

            for (FlwTaskActor taskActor : taskActors) {
                // 只检查用户类型的审批人（actorType = 0）
                if (Objects.equals(0, taskActor.getActorType())) {
                    String actorId = taskActor.getActorId();

                    // 查询该用户是否已经参与过该流程实例
                    Long actorIdLong;
                    try {
                        actorIdLong = Long.parseLong(actorId);
                    } catch (NumberFormatException e) {
                        log.warn("无法将actorId转换为Long类型: {}", actorId);
                        continue;
                    }

                    Integer participationCount = flowlongMapper.selectCountUserParticipatedInInstance(
                            flwTask.getInstanceId(), actorIdLong);

                    if (participationCount != null && participationCount > 0) {
                        hasParticipatedUser = true;
                        participatedActorId = actorId;
                        participatedActorName = taskActor.getActorName();

                        log.info("发现已参与过该流程的审批人，用户ID: {}, 用户名: {}, 参与次数: {}, 实例ID: {}",
                                actorId, taskActor.getActorName(), participationCount, flwTask.getInstanceId());
                        break;
                    }
                }
            }

            if (hasParticipatedUser) {
                // 设置自动审批意见
                FlowHelper.setProcessApprovalOpinion("系统自动通过（该审批人已审批过此流程）");

                // 执行自动跳转
                flowLongEngine.autoJumpTask(flwTask.getId(), FlowCreator.of(
                        flwTask.getTenantId(),
                        participatedActorId,
                        participatedActorName
                ));

                log.info("自动跳过审批成功，任务ID: {}, 实例ID: {}, 审批人: {} ({})",
                        flwTask.getId(), flwTask.getInstanceId(), participatedActorName, participatedActorId);
                return true;
            }

            return false;

        } catch (Exception e) {
            log.error("检查agreeAuto自动跳过逻辑时发生异常，任务ID: {}, 实例ID: {}",
                    flwTask.getId(), flwTask.getInstanceId(), e);
            return false;
        }
    }


    private void contractNumber(FlwTask flwTask) {
        log.info("尝试为合同添加编号，查看当前任务是否为盖章节点，任务信息: {}", JSONUtil.toJsonStr(flwTask));
        Integer taskType = flwTask.getTaskType();
        if (taskType == null || TaskType.seal.getValue() != taskType) {
            return;
        }
        Long instanceId = flwTask.getInstanceId();
        ContractEntity contract = contractService.getOne(Wrappers.<ContractEntity>lambdaQuery()
                .eq(ContractEntity::getApprovalInstanceId, instanceId)
                .last("limit 1"));
        if (null == contract) {
            log.warn("合同信息不存在，无法添加编号，实例ID: {}", instanceId);
            return;
        }
        // 流程结束没有盖章或流程审批完成要进入盖章节点
        ContractNumberEvent contractNumberEvent = new ContractNumberEvent();
        contractNumberEvent.setContractId(contract.getId());
        contractNumberEvent.setGenerateTiming(GenerateTimingEnums.APPROVE);
        log.info("尝试为合同添加编号，查看生成时机是否为审批完成时");
        applicationEventPublisher.publishEvent(contractNumberEvent);
    }

    /**
     * 检查是否为最后一个节点，如果是则更新合同状态
     */
    /**
     * 当归档任务创建时检查并更新合同状态
     * 通过比较parent_task_id来判断盖章节点是否完成
     */
    private void checkAndUpdateContractStatusOnArchiveTaskCreate(FlwTask flwTask) {
        try {
            // 获取流程实例
            FlwInstance instance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
            if (instance == null || instance.getBusinessKey() == null) {
                log.warn("流程实例不存在或businessKey为空，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            // 获取合同信息
            ContractEntity contract = contractService.getById(Integer.valueOf(instance.getBusinessKey()));
            if (contract == null) {
                log.warn("未找到合同信息，businessKey: {}", instance.getBusinessKey());
                return;
            }

            // 检查合同是否已归档
            if (ContractStatusEnum.ARCHIVED.getCode().equals(contract.getCurrentStatus())) {
                log.info("合同已归档，无需更新状态，合同ID: {}", contract.getId());
                return;
            }

            // 获取流程定义信息来获取流程类型
            FlwExtInstance extInstance = flowLongEngine.queryService().getExtInstance(flwTask.getInstanceId());
            if (extInstance == null) {
                log.warn("未找到扩展实例信息，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            log.info("归档任务创建 - 合同ID: {}, 流程类型: {}, 归档任务ID: {}, parent_task_id: {}",
                    contract.getId(), extInstance.getProcessType(), flwTask.getId(), flwTask.getParentTaskId());

            // 只处理business类型的流程
            if ("business".equals(extInstance.getProcessType())) {
                // 归档任务创建说明盖章节点已完成，直接更新合同状态为已盖章
                if (!ContractStatusEnum.SEALED.getCode().equals(contract.getCurrentStatus())) {
                    contract.setCurrentStatus(ContractStatusEnum.SEALED.getCode());
                    boolean updateResult = contractService.updateById(contract);
                    log.info("归档任务创建时更新合同状态为已盖章，合同ID: {}, 更新结果: {}", contract.getId(), updateResult);
                } else {
                    log.info("合同状态已为已盖章，无需重复更新，合同ID: {}", contract.getId());
                }
            }

        } catch (Exception e) {
            log.error("归档任务创建时检查合同状态失败，任务ID: {}", flwTask.getId(), e);
        }
    }

    private void checkAndUpdateContractStatusIfLastNode(FlwTask flwTask) {
        try {
            log.info("开始检查流程是否完全结束并更新合同状态，任务ID: {}, 实例ID: {}",
                    flwTask.getId(), flwTask.getInstanceId());

            // 1. 根据流程实例ID查找关联的合同
            ContractEntity contract = contractService.getOne(
                    new LambdaQueryWrapper<ContractEntity>()
                            .eq(ContractEntity::getApprovalInstanceId, flwTask.getInstanceId())
                            .last("LIMIT 1")
            );

            if (contract == null) {
                log.info("未找到关联的合同，跳过状态更新，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            log.info("找到对应合同，合同ID: {}, 当前状态: {}", contract.getId(), contract.getCurrentStatus());

            // 2. 检查合同状态，如果已归档则不允许修改
            if (ContractStatusEnum.ARCHIVED.getCode().equals(contract.getCurrentStatus())) {
                log.info("合同已归档，跳过状态更新，合同ID: {}, 当前状态: {}", contract.getId(), contract.getCurrentStatus());
                return;
            }

            // 3. 获取流程实例信息
            FlwInstance activeInstance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
            if (activeInstance == null) {
                log.info("流程实例不在活跃状态，跳过状态更新，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            // 4. 检查是否为子流程，子流程不更新合同状态
            if (activeInstance.getParentInstanceId() != null) {
                log.info("流程实例是子流程（父实例ID: {}），跳过合同状态更新，实例ID: {}",
                        activeInstance.getParentInstanceId(), flwTask.getInstanceId());
                return;
            }

            // 5. 获取流程定义信息，检查ProcessType
            FlwExtInstance extInstance = flowLongEngine.queryService().getExtInstance(flwTask.getInstanceId());
            if (extInstance == null) {
                log.warn("未找到扩展实例信息，跳过状态更新，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            String processType = extInstance.getProcessType();
            log.info("流程类型: {}", processType);

            // 6. 检查流程实例是否还有其他活跃任务（关键逻辑：判断整个流程是否完全结束）
            List<FlwTask> allActiveTasks = flowLongEngine.queryService().getActiveTasksByInstanceId(flwTask.getInstanceId())
                    .orElse(java.util.Collections.emptyList());

            // 过滤掉当前完成的任务（因为当前任务可能还在活跃任务列表中）
            List<FlwTask> remainingActiveTasks = allActiveTasks.stream()
                    .filter(task -> !Objects.equals(task.getId(), flwTask.getId()))
                    .collect(java.util.stream.Collectors.toList());

            log.info("流程实例 {} 的活跃任务总数: {}, 除当前任务外的剩余活跃任务数: {}",
                    flwTask.getInstanceId(), allActiveTasks.size(), remainingActiveTasks.size());

            // 如果还有其他活跃任务，说明流程还没有完全结束
            if (!remainingActiveTasks.isEmpty()) {
                log.info("流程还有其他活跃任务未完成，暂不更新合同状态，当前任务ID: {}, 剩余活跃任务数: {}",
                        flwTask.getId(), remainingActiveTasks.size());
                // 打印剩余任务信息用于调试
                for (FlwTask remainingTask : remainingActiveTasks) {
                    log.info("剩余活跃任务 - ID: {}, 节点Key: {}, 任务名称: {}",
                            remainingTask.getId(), remainingTask.getTaskKey(), remainingTask.getTaskName());
                }
                return;
            }

            log.info("流程实例 {} 已无其他活跃任务，准备检查是否需要更新合同状态", flwTask.getInstanceId());

            // 7. 只有当ProcessType为business时才更新合同状态
            if (ProcessType.business.eq(processType)) {
                // 获取当前任务的节点信息，根据节点类型设置对应的合同状态
                ProcessModel processModel = flowLongEngine.runtimeService().getProcessModelByInstanceId(flwTask.getInstanceId());
                NodeModel currentNodeModel = processModel.getNode(flwTask.getTaskKey());

                if (currentNodeModel != null) {
                    Integer nodeType = currentNodeModel.getType();
                    String newStatus = null;

                    // 只处理盖章节点和归档节点
                    if (TaskType.seal.eq(nodeType)) {
                        // 盖章节点(100) -> SEALED状态
                        newStatus = ContractStatusEnum.SEALED.getCode();
                        log.info("盖章节点完成，设置合同状态为SEALED");
                    } else if (TaskType.archive.eq(nodeType)) {
                        // 归档节点(101) -> ARCHIVED状态
                        newStatus = ContractStatusEnum.ARCHIVED.getCode();
                        log.info("归档节点完成，设置合同状态为ARCHIVED");
                    } else {
                        log.info("非盖章/归档节点(类型: {})，跳过合同状态更新，实例ID: {}", nodeType, flwTask.getInstanceId());
                    }

                    // 更新合同状态
                    if (newStatus != null) {
                        contract.setCurrentStatus(newStatus);
                        boolean updateResult = contractService.updateById(contract);

                        if (updateResult) {
                            log.info("业务流程节点完成，合同状态更新成功，合同ID: {}, 新状态: {}", contract.getId(), newStatus);
                        } else {
                            log.warn("业务流程节点完成，合同状态更新失败，合同ID: {}", contract.getId());
                        }
                    }
                } else {
                    log.warn("无法获取当前节点信息，跳过状态更新，任务ID: {}, 节点Key: {}", flwTask.getId(), flwTask.getTaskKey());
                }
            } else {
                log.info("非业务流程（ProcessType: {}），跳过合同状态更新，实例ID: {}", processType, flwTask.getInstanceId());
            }

        } catch (Exception e) {
            log.error("检查并更新合同状态失败，任务ID: {}", flwTask.getId(), e);
        }
    }

    /**
     * 检查任务执行前是否为最后节点
     */
    private boolean checkIfLastNodeBeforeExecution(FlwTask flwTask) {
        try {
            // 使用现有的 listNextNodes 方法来判断
            NextNodesDTO nextNodesDTO = new NextNodesDTO();
            nextNodesDTO.setInstanceId(flwTask.getInstanceId());
            Map<String, Object> nextNodesResult = flwProcessTaskService.listNextNodes(nextNodesDTO);

            // 如果没有下一个节点或者nodeCount为0，说明是最后一个节点
            Object nodeCount = nextNodesResult.get("nodeCount");
            boolean isLastNode = (nodeCount == null || Integer.valueOf(0).equals(nodeCount));

            log.info("检查任务节点 {} 的下一个节点，下一个节点数量: {}, 是否最后节点: {}",
                    flwTask.getTaskKey(),
                    nodeCount,
                    isLastNode);

            return isLastNode;

        } catch (Exception e) {
            log.error("检查是否为最后节点时发生异常，任务ID: {}, 节点Key: {}",
                    flwTask.getId(), flwTask.getTaskKey(), e);
            return false;
        }
    }

    /**
     * 根据任务类型确定合同状态
     *
     * @param taskType 任务类型
     * @return 合同状态
     */
    private String determineContractStatusByTaskType(Integer taskType) {
        if (taskType == null) {
            log.warn("任务类型为空，使用默认状态APPROVED");
            return ContractStatusEnum.APPROVED.getCode();
        }

        // 根据TaskType枚举判断
        if (TaskType.seal.eq(taskType)) {
            // 盖章节点(100) -> SEALED状态
            log.info("盖章节点审批完成，设置合同状态为SEALED");
            return ContractStatusEnum.SEALED.getCode();
        } else if (TaskType.archive.eq(taskType)) {
            // 归档节点(101) -> ARCHIVED状态
            log.info("归档节点审批完成，设置合同状态为ARCHIVED");
            return ContractStatusEnum.ARCHIVED.getCode();
        } else {
            // 其他节点 -> APPROVED状态
            log.info("普通审批节点完成，设置合同状态为APPROVED");
            return ContractStatusEnum.APPROVED.getCode();
        }
    }

    /**
     * 从sys_user表补充抄送用户的完整信息
     * @param ccUsers 抄送用户列表
     * @return 补充完整信息后的抄送用户列表
     */
    private List<NodeAssignee> enrichCcUsersFromSysUser(List<NodeAssignee> ccUsers) {
        if (CollectionUtils.isEmpty(ccUsers)) {
            return new ArrayList<>();
        }

        try {
            // 获取用户ID列表
            List<Long> userIds = ccUsers.stream()
                    .map(user -> Long.valueOf(user.getId()))
                    .distinct()
                    .collect(Collectors.toList());

            // 从sys_user表查询用户信息
            List<SysUser> users = sysUserService.listByIds(userIds);
            Map<Long, SysUser> userMap = users.stream()
                    .collect(Collectors.toMap(SysUser::getId, user -> user));

            // 补充用户信息
            return ccUsers.stream()
                    .map(ccUser -> {
                        Long userId = Long.valueOf(ccUser.getId());
                        SysUser sysUser = userMap.get(userId);
                        if (sysUser != null) {
                            ccUser.setName(sysUser.getRealName());
                            // 头像用extendconfig包装
                            if (StringUtils.hasLength(sysUser.getAvatar())) {
                                Map<String, Object> extendConfig = new HashMap<>();
                                extendConfig.put("avatar", sysUser.getAvatar());
                                ccUser.setExtendConfig(extendConfig);
                            }
                        }
                        return ccUser;
                    })
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("补充抄送用户信息失败", e);
            return ccUsers; // 返回原始数据
        }
    }

    /**
     * 根据任务ID查询当前任务的抄送用户列表
     * @param taskId 任务ID
     * @return 抄送用户列表
     */
    private List<NodeAssignee> getCcUsersByTaskId(Long taskId) {
        try {
            // 首先检查当前任务是否为抄送任务
            FlwHisTask hisTask = flowLongEngine.queryService().getHistTask(taskId);
            if (hisTask == null || hisTask.getTaskType() == null || hisTask.getTaskType() != 2) {
                // 不是抄送任务，返回空列表
                return new ArrayList<>();
            }

            // 查询历史任务执行者
            List<FlwHisTaskActor> hisTaskActors = flowLongEngine.queryService().getHisTaskActorsByTaskId(taskId);
            if (CollectionUtils.isEmpty(hisTaskActors)) {
                return new ArrayList<>();
            }

            // 转换为NodeAssignee列表
            List<NodeAssignee> ccUsers = hisTaskActors.stream()
                    .map(actor -> {
                        NodeAssignee nodeAssignee = new NodeAssignee();
                        nodeAssignee.setId(actor.getActorId());
                        return nodeAssignee;
                    })
                    .collect(Collectors.toList());

            // 使用enrichCcUsersFromSysUser方法补充用户信息
            return this.enrichCcUsersFromSysUser(ccUsers);
        } catch (Exception e) {
            log.error("查询抄送用户失败，taskId: {}", taskId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 设置子流程的business_key
     * 当主流程激活子流程时，将主流程的合同ID传递给子流程
     */
    private void setSubProcessBusinessKey(FlwTask flwTask, NodeModel nodeModel) {
        try {
            log.info("开始设置子流程business_key，主流程任务ID: {}, 实例ID: {}, 节点Key: {}",
                    flwTask.getId(), flwTask.getInstanceId(), flwTask.getTaskKey());

            // 1. 获取主流程实例的business_key
            FlwInstance mainInstance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
            if (mainInstance == null || mainInstance.getBusinessKey() == null || mainInstance.getBusinessKey().trim().isEmpty()) {
                log.warn("主流程实例不存在或business_key为空，无法设置子流程business_key，实例ID: {}", flwTask.getInstanceId());
                return;
            }

            String mainBusinessKey = mainInstance.getBusinessKey();
            log.info("获取到主流程business_key: {}", mainBusinessKey);

            // 2. 从callProcess中提取子流程实例ID
            String callProcess = nodeModel.getCallProcess();
            if (callProcess == null || callProcess.trim().isEmpty()) {
                log.warn("节点callProcess为空，无法获取子流程实例ID");
                return;
            }

            // callProcess格式可能是 "processKey:instanceId" 或 "processId:processName:instanceId"
            String[] parts = callProcess.split(":");
            if (parts.length < 2) {
                log.warn("callProcess格式不正确，无法解析子流程实例ID: {}", callProcess);
                return;
            }

            // 获取最后一部分作为实例ID
            String subInstanceIdStr = parts[parts.length - 1];
            Long subInstanceId;
            try {
                subInstanceId = Long.parseLong(subInstanceIdStr);
            } catch (NumberFormatException e) {
                log.warn("无法解析子流程实例ID: {}", subInstanceIdStr);
                return;
            }

            log.info("解析到子流程实例ID: {}", subInstanceId);

            // 3. 更新子流程实例的business_key
            FlwInstance subInstance = flowLongEngine.queryService().getInstance(subInstanceId);
            if (subInstance == null) {
                log.warn("子流程实例不存在，实例ID: {}", subInstanceId);
                return;
            }

            // 设置子流程的business_key与主流程相同
            subInstance.setBusinessKey(mainBusinessKey);

            // 更新数据库（updateInstance方法没有返回值）
            flowLongEngine.runtimeService().updateInstance(subInstance);
            log.info("成功设置子流程business_key，子流程实例ID: {}, business_key: {}",
                    subInstanceId, mainBusinessKey);

        } catch (Exception e) {
            log.error("设置子流程business_key时发生异常，任务ID: {}", flwTask.getId(), e);
        }
    }
}
